lib: add utility function for getting random data
authorFelix Fietkau <[email protected]>
Mon, 2 Jun 2025 20:26:58 +0000 (22:26 +0200)
committerFelix Fietkau <[email protected]>
Tue, 8 Jul 2025 21:37:40 +0000 (23:37 +0200)
Try getrandom/arc4random first, only fall back to /dev/urandom when necessary

Signed-off-by: Felix Fietkau <[email protected]>
CMakeLists.txt
cli.c
enroll.c
pex-msg.c
random.c [new file with mode: 0644]
random.h [new file with mode: 0644]
stun.c
token.c

index aba97870ecc7a54553b939f4951aacaf7057b2a2..58ea9962e1311ae729a81ac871468c9135155902 100644 (file)
@@ -46,7 +46,7 @@ ELSE()
   SET(udebug "")
 ENDIF()
 
-ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c chacha20.c pex-msg.c utils.c stun.c)
+ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c chacha20.c pex-msg.c utils.c stun.c random.c)
 TARGET_LINK_LIBRARIES(unet ubox)
 
 ADD_EXECUTABLE(unetd ${SOURCES})
diff --git a/cli.c b/cli.c
index c3403a3b241a8fc4c6b71ffd8c9239284809bba6..d110dd575dd5d3c0c9690bd96bda9fd160d326fa 100644 (file)
--- a/cli.c
+++ b/cli.c
@@ -23,6 +23,7 @@
 #include "ed25519.h"
 #include "curve25519.h"
 #include "auth-data.h"
+#include "random.h"
 #include "pex-msg.h"
 
 static uint8_t peerkey[EDSIGN_PUBLIC_KEY_SIZE];
@@ -438,26 +439,10 @@ static int cmd_pubkey(int argc, char **argv)
 
 static int generate_key(void)
 {
-       FILE *f;
-       int ret;
-
        if (has_key)
                return 0;
 
-       f = fopen("/dev/urandom", "r");
-       if (!f) {
-               INFO("Can't open /dev/urandom\n");
-               return 1;
-       }
-
-       ret = fread(seckey, sizeof(seckey), 1, f);
-       fclose(f);
-
-       if (ret != 1) {
-               INFO("Can't read data from /dev/urandom\n");
-               return 1;
-       }
-
+       randombytes(seckey, sizeof(seckey));
        ed25519_prepare(seckey);
        has_key = true;
 
index a8ec7063337834edf5adbfed4981062ba68ff349..20808f60857e1d0042ec5c9db53616d0e6269d6b 100644 (file)
--- a/enroll.c
+++ b/enroll.c
@@ -9,6 +9,7 @@
 #include "sha512.h"
 #include "chacha20.h"
 #include "unetd.h"
+#include "random.h"
 #include <libubus.h>
 #include <libubox/blobmsg_json.h>
 
@@ -733,9 +734,8 @@ int enroll_start(struct blob_attr *data)
        struct blob_attr *meta_buf, *enroll_meta_buf;
        unsigned int timeout, interval;
        struct network *net = NULL;
-       int n_connect = 0, err = 0;
+       int n_connect = 0;
        size_t rem;
-       FILE *f;
 
        enroll_stop();
        blobmsg_parse_attr(enroll_start_policy, __ENROLL_START_ATTR_MAX, tb, data);
@@ -795,16 +795,7 @@ int enroll_start(struct blob_attr *data)
                state->n_connect++;
        }
 
-       f = fopen("/dev/urandom", "r");
-       if (!f)
-               return UBUS_STATUS_UNKNOWN_ERROR;
-
-       if (fread(state->privkey, sizeof(state->privkey), 1, f) != 1)
-           err = UBUS_STATUS_UNKNOWN_ERROR;
-
-       fclose(f);
-       if (err)
-           goto error;
+       randombytes(state->privkey, sizeof(state->privkey));
 
        curve25519_clamp_secret(state->privkey);
        curve25519_generate_public(state->pubkey, state->privkey);
@@ -827,11 +818,6 @@ int enroll_start(struct blob_attr *data)
                uloop_timeout_set(&state->connect_timer, 10);
 
        return 0;
-
-error:
-       free(state);
-       state = NULL;
-       return err;
 }
 
 void enroll_stop(void)
index 34b3bb99b889ff5eb82fcefdb4a1bd2052330cff..21384d0c948a76a9141fb58364079ea9140c8b48 100644 (file)
--- a/pex-msg.c
+++ b/pex-msg.c
 #include <libubox/list.h>
 #include <libubox/uloop.h>
 #include <libubox/usock.h>
+#include "random.h"
 #include "pex-msg.h"
 #include "chacha20.h"
 #include "auth-data.h"
 
 static char pex_tx_buf[PEX_BUF_SIZE];
-static FILE *pex_urandom;
 static struct uloop_fd pex_fd, pex_unix_fd;
 static LIST_HEAD(requests);
 static struct uloop_timeout gc_timer;
@@ -113,9 +113,7 @@ struct pex_hdr *__pex_msg_init_ext(const uint8_t *pubkey, const uint8_t *auth_ke
 
        hdr->len = sizeof(*ehdr);
 
-       if (fread(&ehdr->nonce, sizeof(ehdr->nonce), 1, pex_urandom) != 1)
-               return NULL;
-
+       randombytes(&ehdr->nonce, sizeof(ehdr->nonce));
        hash = pex_network_hash(auth_key, ehdr->nonce);
        *(uint64_t *)hdr->id ^= hash;
        memcpy(ehdr->auth_id, auth_key, sizeof(ehdr->auth_id));
@@ -374,8 +372,7 @@ void pex_msg_update_response_init(struct pex_msg_update_send_ctx *ctx,
        res->req_id = req->req_id;
        res->data_len = cpu_to_be32(len);
 
-       if (!fread(e_key_priv, sizeof(e_key_priv), 1, pex_urandom))
-               return;
+       randombytes(e_key_priv, sizeof(e_key_priv));
 
        curve25519_clamp_secret(e_key_priv);
        curve25519_generate_public(res->e_key, e_key_priv);
@@ -431,10 +428,7 @@ pex_msg_update_request_init(const uint8_t *pubkey, const uint8_t *priv_key,
        memcpy(&ctx->addr, addr, sizeof(ctx->addr));
        memcpy(ctx->auth_key, auth_key, sizeof(ctx->auth_key));
        memcpy(ctx->priv_key, priv_key, sizeof(ctx->priv_key));
-       if (!fread(&ctx->req_id, sizeof(ctx->req_id), 1, pex_urandom)) {
-               free(ctx);
-               return NULL;
-       }
+       randombytes(&ctx->req_id, sizeof(ctx->req_id));
        list_add_tail(&ctx->list, &requests);
        if (!gc_timer.pending)
                uloop_timeout_set(&gc_timer, 1000);
@@ -621,13 +615,9 @@ int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server)
 #endif
        }
 
-       pex_urandom = fopen("/dev/urandom", "r");
-       if (!pex_urandom)
-               goto close_raw;
-
        fd = socket(sa->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
        if (fd < 0)
-               goto close_urandom;
+               goto close_raw;
 
        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
        fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
@@ -659,8 +649,6 @@ int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server)
 
 close_socket:
        close(fd);
-close_urandom:
-       fclose(pex_urandom);
 close_raw:
        if (pex_raw_v4_fd >= 0)
                close(pex_raw_v4_fd);
@@ -701,9 +689,6 @@ void pex_close(void)
        pex_raw_v4_fd = -1;
        pex_raw_v6_fd = -1;
 
-       if (pex_urandom)
-               fclose(pex_urandom);
-
        if (pex_fd.cb) {
                uloop_fd_delete(&pex_fd);
                close(pex_fd.fd);
@@ -716,5 +701,4 @@ void pex_close(void)
 
        pex_fd.cb = NULL;
        pex_unix_fd.cb = NULL;
-       pex_urandom = NULL;
 }
diff --git a/random.c b/random.c
new file mode 100644 (file)
index 0000000..dc8a2c2
--- /dev/null
+++ b/random.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Felix Fietkau <[email protected]>
+ */
+#ifdef linux
+#include <sys/ramdom.h>
+#endif
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+ssize_t __getrandom(void *buf, size_t buflen)
+{
+       static FILE *urandom;
+       ssize_t ret;
+
+#ifdef linux
+       ret = getrandom(buf, buflen, 0);
+       if (ret > 0)
+               return ret;
+#endif
+
+#ifdef __APPLE__
+       arc4random_buf(buf, buflen);
+       return buflen;
+#endif
+
+       if (!urandom) {
+               urandom = fopen("/dev/urandom", "r");
+               if (!urandom)
+                       abort();
+       }
+
+       ret = fread(buf, buflen, 1, urandom);
+       if (ret != 1)
+               return -1;
+
+       return buflen;
+}
+
+void randombytes(void *buf, size_t len)
+{
+       while (len > 0) {
+               ssize_t cur = len;
+
+               if (cur > 256)
+                       cur = 256;
+
+               cur = __getrandom(buf, cur);
+               if (cur < 0)
+                       continue;
+
+               buf += cur;
+               len -= cur;
+       }
+}
diff --git a/random.h b/random.h
new file mode 100644 (file)
index 0000000..10d25f6
--- /dev/null
+++ b/random.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Felix Fietkau <[email protected]>
+ */
+#ifndef __UNET_RANDOM_H
+#define __UNET_RANDOM_H
+
+#include <stdlib.h>
+
+void randombytes(void *buf, size_t len);
+
+#endif
diff --git a/stun.c b/stun.c
index 47e8b7bb464f2b1907fb016cb4d2d6f62ba33f0f..eb5c096147ef7c5ad0112c7b4cff2b622c1d35ce 100644 (file)
--- a/stun.c
+++ b/stun.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdio.h>
 #include "stun.h"
+#include "random.h"
 
 static uint8_t tx_buf[256];
 
@@ -105,7 +106,6 @@ const void *stun_msg_request_prepare(struct stun_request *req, size_t *len,
                                     uint16_t response_port)
 {
        struct stun_msg_hdr *hdr;
-       FILE *f;
 
        hdr = stun_msg_init(STUN_MSGTYPE_BINDING_REQUEST);
        if (response_port) {
@@ -113,14 +113,7 @@ const void *stun_msg_request_prepare(struct stun_request *req, size_t *len,
                *tlv_port = htons(response_port);
        }
 
-       f = fopen("/dev/urandom", "r");
-       if (!f)
-               return NULL;
-
-       if (fread(hdr->transaction, 12, 1, f) != 1)
-               return NULL;
-
-       fclose(f);
+       randombytes(hdr->transaction, 12);
        memcpy(req->transaction, hdr->transaction, sizeof(req->transaction));
        req->pending = true;
        req->port = 0;
diff --git a/token.c b/token.c
index e54d1fdb731da9b3a51c4440d60591f9d4fd859d..3210d49628e0a3a4f5ece365037f86ccb6334076 100644 (file)
--- a/token.c
+++ b/token.c
@@ -5,6 +5,7 @@
 #include <time.h>
 #include "unetd.h"
 #include "sha512.h"
+#include "random.h"
 
 static uint8_t salt[8];
 static uint64_t nonce;
@@ -19,17 +20,12 @@ struct token_hdr {
 static bool token_init(void)
 {
        static bool init_done;
-       FILE *f;
 
        if (init_done)
                return true;
 
-       f = fopen("/dev/urandom", "r");
-       if (!f)
-               return false;
-
-       init_done = fread(salt, sizeof(salt), 1, f) == 1;
-       fclose(f);
+       init_done = true;
+       randombytes(salt, sizeof(salt));
 
        return init_done;
 }